#include <QString>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QMenu>
#include <QMenuBar>
#include <QGroupBox>
#include <QComboBox>
#include <QCheckBox>
#include <QPushButton>
#include <QSpinBox>
#include <QProgressBar>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>

#include <QStackedWidget>
#include <QBuffer>
#include <QMessageBox>
#include <QApplication>
#include <QPainter>

#include <QFileDialog>
#include <QSqlDatabase>
#include <QInputDialog>
#include <QtPlugin>

#include <mainwindow.hpp>
#include <qwebcam.hpp>

#include <cv.h>
//#include <stdio.h>
#include <cxcore.h>

#define PROGRESS_MESSAGE(x, n) \
    m_Progress->setValue(n); \
    m_PLabel->setText(x); \
    QApplication::processEvents()

#ifdef STATIC_PSQL_PLUGIN
Q_IMPORT_PLUGIN(qsqlpsql)
#endif
Q_DECLARE_METATYPE(char *)

MainWindow::MainWindow(QWidget *parent):
    QMainWindow(parent),
    m_DeviceList(NULL),
    m_Resolutions(NULL),
    m_Webcam(new QWebcam(this)),
    m_CLImageCount(NULL),
    m_HorzCorners(NULL),
    m_VertCorners(NULL),
    m_Progress(NULL),
    m_PLabel(NULL),
    m_BTools(new QTabWidget(this)),
    m_Plot(new QwtPlot(this)),
    m_Stacked(new QStackedWidget(this)),
    m_Tracker(NULL)
{
}

void
MainWindow::initialize()
{
    QHBoxLayout     *layout;
    QWidget         *widget;
    QWidget         *wCamConf;
    QWidget         *wCamCal;
    QMenu           *menu;
    QAction         *action;
    QSqlDatabase     db;

    widget   = new QWidget(this);
    layout   = new QHBoxLayout(widget);
    wCamConf = createCameraConfigurationWidget();
    wCamCal  = createCameraCalibrationWidget();
    menu     = new QMenu("&Archivo", this);
    action   = new QAction(QIcon(":/save"), "&Guardar Trayectoria", this);

    db = QSqlDatabase::addDatabase("QPSQL");

    db.setDatabaseName("trazoscopio");
    db.setUserName("postgres");
    db.setPassword("123456");

    if (!db.open()) {
        /*QMessageBox msgbox;

        msgbox.setText("No se pudo conectar a la base de datos.");
        msgbox.setDetailedText(db.lastError().text());
        msgbox.setIcon(QMessageBox::Critical);
        msgbox.setStandardButtons(QMessageBox::Ok);

        msgbox.exec();*/
    }
    connect(action, SIGNAL(triggered()), SLOT(save()));
    menu->addAction(action);

    action = new QAction(QIcon(":/close"), "&Salir", this);

    connect(action, SIGNAL(triggered()), SLOT(close()));
    menu->addAction(action);

    m_BTools->addTab(wCamConf, QIcon(), "C\xe1mara");
    m_BTools->addTab(wCamCal, QIcon(), "Calibraci\xf3n");
    m_BTools->setFixedWidth(250);
    m_BTools->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
    m_Webcam->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

    layout->addWidget(m_BTools);
    layout->addWidget(m_Stacked);

    m_Stacked->addWidget(m_Webcam);
    m_Stacked->addWidget(m_Plot);

    if (menuBar())
        menuBar()->addMenu(menu);

    loadDevicesList();
    loadDeviceResolutions();

    m_Plot->setCanvasBackground(QColor(Qt::white));
    connectDevice(0);

    m_Tracker = new TCTracker(loadDeviceFrameRates(), this);

    if (!m_Tracker)
        return;

    m_Webcam->setTracker(m_Tracker);
    m_Tracker->setPlotter(m_Plot);

    setCentralWidget(widget);
    updateImageCount();
}

void
MainWindow::changeColor(QColor)
{
}

void
MainWindow::loadDevicesList()
{
    if (!m_DeviceList)
        return;

    CPCapDeviceEnumerator *info;

    info = new CPCapDeviceEnumerator();
    if (!info) {
        fprintf(stderr, "error: no se pudieron listar los dispositivos.\n");
        return;
    }

    while (info->next()) {
        const char  *name;
        QString     uid;

        name = info->name();
        uid  = QString(info->uid());

        m_DeviceList->addItem(QIcon(":/webcam"), name, uid);
    }

    if (m_DeviceList->count() <= 1) {
        if (m_DeviceList->count() == 0)
            m_DeviceList->addItem("Valor Fijo");
        m_DeviceList->setEnabled(false);
    }

    if (info)
        delete info;
}

QWidget *
MainWindow::createCameraConfigurationWidget()
{
    QGridLayout *layout;
    QVBoxLayout *central;
    QWidget     *widget;
    QLabel      *label;
    int          row;
    QComboBox   *combo;
    QToolButton *clear;

    widget        = new QWidget(this);
    central       = new QVBoxLayout(widget);
    layout        = new QGridLayout;
    m_DeviceList  = new QComboBox(this);
    m_Resolutions = new QComboBox(this);
    combo         = new QComboBox(this);
    clear         = new QToolButton(this);

    clear->setIcon(QIcon::fromTheme("edit-clear", QIcon(":/clear")));

    m_Resolutions->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
    m_DeviceList->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);

    row   = 0;
    label = new QLabel("Dispositivo", this);

    layout->addWidget(label, row, 0, 1, 1, Qt::AlignRight);
    layout->addWidget(m_DeviceList, row++, 1, 1, 1);

    label  = new QLabel("Resoluci\xf3n", this);
    layout->addWidget(label, row, 0, 1, 1, Qt::AlignRight);
    layout->addWidget(m_Resolutions, row++, 1, 1, 1);

    label = new QLabel("Vista", this);
    layout->addWidget(label, row, 0, 1, 1, Qt::AlignRight);
    layout->addWidget(combo, row++, 1, 1, 2, Qt::AlignLeft | Qt::AlignVCenter);

    label = new QLabel("Limpiar", this);
    layout->addWidget(label, row, 0, 1, 1, Qt::AlignRight);
    layout->addWidget(clear, row++, 1, 1, 2, Qt::AlignLeft | Qt::AlignVCenter);

    combo->addItem("C\xe1mara");
    combo->addItem("Trayectoria");

    connect(clear, SIGNAL(clicked()), SLOT(clearPlot()));
    connect(combo, SIGNAL(currentIndexChanged(int)), m_Stacked,
            SLOT(setCurrentIndex(int)));

    connect(m_Resolutions, SIGNAL(activated(int)), SLOT(changeResolution(int)));
    connect(m_DeviceList, SIGNAL(activated(int)), SLOT(connectDevice(int)));
    connect(m_Webcam, SIGNAL(areaSelected()), SLOT(areaSelected()));
    connect(m_Webcam, SIGNAL(trackingStoped()), SLOT(onTrackingStoped()));

    central->addLayout(layout);
    central->addStretch();

    widget->setMaximumWidth(250);
    return widget;
}

void
MainWindow::setColor()
{
}

QWidget *
MainWindow::createCameraCalibrationWidget()
{
    QWidget      *widget    = NULL;
    QGridLayout  *layout    = NULL;
    QVBoxLayout  *central   = NULL;
    QPushButton  *button    = NULL;
    QPushButton  *calculate = NULL;
    QPushButton  *details   = NULL;

    widget         = new QWidget(this);
    central        = new QVBoxLayout(widget);
    layout         = new QGridLayout;
    m_HorzCorners  = new QSpinBox(this);
    m_VertCorners  = new QSpinBox(this);
    m_CLImageCount = new QLabel(this);
    button         = new QPushButton(this);
    m_Progress     = new QProgressBar(this);
    m_PLabel       = new QLabel(this);
    calculate      = new QPushButton(this);
    details        = new QPushButton(this);

    m_HorzCorners->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
    m_VertCorners->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);

    layout->addWidget(new QLabel("N\xfamero de Esquinas", this), 0, 0, 1, 3);
    layout->addWidget(new QLabel("Horizontales", this), 1, 1, 1, 1, \
                      Qt::AlignVCenter | Qt::AlignRight);
    layout->addWidget(m_HorzCorners, 1, 2, 1, 1);
    layout->addWidget(new QLabel("Verticales", this), 2, 1, 1, 1, \
                      Qt::AlignVCenter | Qt::AlignRight);
    layout->addWidget(m_VertCorners, 2, 2, 1, 1);

    layout->addWidget(button, 3, 1, 1, 1,
                      Qt::AlignVCenter | Qt::AlignRight);
    layout->addWidget(new QLabel("Analizar", this), 3, 2, 1, 1, \
                      Qt::AlignVCenter | Qt::AlignLeft);

    layout->addWidget(calculate, 4, 1, 1, 1,
                      Qt::AlignVCenter | Qt::AlignRight);
    layout->addWidget(new QLabel("Calcular", this), 4, 2, 1, 1, \
                      Qt::AlignVCenter | Qt::AlignLeft);

    layout->addWidget(details, 5, 1, 1, 1,
                      Qt::AlignVCenter | Qt::AlignRight);
    layout->addWidget(new QLabel("Detalles", this), 5, 2, 1, 1, \
                      Qt::AlignVCenter | Qt::AlignLeft);

    button->setMaximumSize(32, 32);
    button->setIcon(QIcon(":/save"));

    calculate->setMaximumSize(32, 32);
    calculate->setIcon(QIcon(":/calculate"));

    details->setMaximumSize(32, 32);
    details->setIcon(QIcon(":/more"));

    m_CLImageCount->setAlignment(Qt::AlignCenter);
    m_CLImageCount->setFont(QFont("Monospace", 72));
    m_CLImageCount->setText("0");

    m_PLabel->setText("Inactivo");

    central->addLayout(layout);
    central->addStretch();
    central->addWidget(m_CLImageCount);
    central->addWidget(m_PLabel, 0, Qt::AlignLeft | Qt::AlignVCenter);
    central->addWidget(m_Progress);

    connect(button, SIGNAL(clicked()), SLOT(storeCalibrationImage()));
    connect(calculate, SIGNAL(clicked()), SLOT(computeCalibrationParameters()));
    connect(details, SIGNAL(clicked()), SLOT(showCalibrationDetails()));

    m_HorzCorners->setValue(7);
    m_VertCorners->setValue(7);

    widget->setMaximumWidth(250);
    return widget;
}

void
MainWindow::storeCalibrationImage()
{
    if (m_HorzCorners->value() == 0 || m_VertCorners->value() == 0)
        return;

    m_BTools->setEnabled(false);
    PROGRESS_MESSAGE("Procesando", 10);

    static int    imgcount = 0;

    QImage        qimage(m_Webcam->capture());
    CvMat        *image   = NULL;
    CvSize        size    = {m_HorzCorners->value(), m_VertCorners->value()};
    int           count   = 0;
    CvPoint2D32f *corners = NULL;
    int           lcc     = size.width * size.height;

    image   = cvCreateMatHeader(qimage.height(), qimage.width(), CV_8UC3);
    corners = new CvPoint2D32f[lcc];

    PROGRESS_MESSAGE("Procesando..", 20);
    cvSetData(image, qimage.bits(), qimage.bytesPerLine());

    PROGRESS_MESSAGE("Procesando..", 30);
    PROGRESS_MESSAGE("Procesando...", 50);

    if (cvFindChessboardCorners(image, size, corners, &count) > 0) {
        QByteArray   ba;
        QBuffer      buffer(&ba);
        QSqlQuery    query;
#ifdef Q_OS_LINUX
        char         imgname[128] = {0};
#endif
        CvMat	    *gray;
        QSqlDatabase db;

        if (db.isOpen()) {
            qimage.save(&buffer, "PNG");
            buffer.open(QIODevice::WriteOnly);

            query.prepare("INSERT INTO imagenes_de_calibracion " \
                          "(data, vertical, horizontal, resolution) VALUES " \
                          "(:data, :vertical, :horizontal, :resolution)");
            query.bindValue(0, buffer.data());
            query.bindValue(1, m_VertCorners->value());
            query.bindValue(2, m_HorzCorners->value());
            query.bindValue(3, m_Resolutions->currentIndex());

            buffer.close();
            if (!query.exec()) {
                /* FIXME: show error */
            }
        }
#ifdef Q_OS_LINUX
        snprintf(imgname, 128, "/home/ecologia-sensorial/imagen-calibracion-%04d.png", ++imgcount);
#else
#endif

        gray = cvCreateMat(qimage.height(), qimage.width(), CV_8U);

        cvCvtColor(image, gray, CV_RGB2GRAY);
        cvDrawChessboardCorners(gray, size, corners, count, true);
#ifdef Q_OS_LINUX
        cvSaveImage(imgname, gray);
#endif
        cvReleaseMat(&gray);

        updateImageCount();
    }
    cvDecRefData(&image);
    cvReleaseMat(&image);
    free(corners);

    PROGRESS_MESSAGE("Procesando", 50);
    PROGRESS_MESSAGE("Procesando...", 100);

    PROGRESS_MESSAGE("Inactivo", 0);
    m_BTools->setEnabled(true);
}

void
MainWindow::loadDeviceResolutions()
{
    if (!m_Webcam)
        return;

    QWebcamResolutionList info;

    info = m_Webcam->resolutionsList();

    m_Resolutions->clear();
    for (int i = 0 ; i < info.count() ; i++) {
        QString name;

        name = QString("%1x%2 %4")
                .arg(info[i].width)
                .arg(info[i].height)
                .arg(info[i].name);
        m_Resolutions->addItem(name, qVariantFromValue(info[i]));
    }

    if (info.count() > 0)
        m_Webcam->setResolution(info[0]);
}

void
MainWindow::connectDevice(int index)
{
    if (!m_Webcam)
        return;

    QString name;
    QString uid;

    name = m_DeviceList->itemText(index);
    uid  = m_DeviceList->itemData(index).value<QString>();

    m_Webcam->setDevice(uid.toAscii().data(), name.toAscii().data());

    loadDeviceResolutions();
}

void
MainWindow::changeResolution(int index)
{
    if (!m_Webcam || !m_Tracker)
        return;
    QWebcamResolution info;

    info = qvariant_cast<QWebcamResolution>(m_Resolutions->itemData(index));

    m_Webcam->setResolution(info);
    m_Tracker->setFPS(loadDeviceFrameRates());
}

int
MainWindow::loadDeviceFrameRates()
{
    QWebcamFrameRateList    frl;
    QWebcamResolution       info;
    int                     index;
    int                     fps;

    index = m_Resolutions->currentIndex();
    info  = qvariant_cast<QWebcamResolution>(m_Resolutions->itemData(index));

    frl = m_Webcam->framerateList(info);
    fps = 0;

    for (int i = 0 ; i < frl.count() ; i++) {
        if (frl[i].fps > fps)
            fps = frl[i].fps;
    }

    return fps;
}

void
MainWindow::showRGB(bool enable)
{
    if (!m_Webcam)
        return;

    m_Webcam->enableRGBTrace(enable);
}

void
MainWindow::pickArea(bool)
{
    if (!m_Webcam)
        return;
}

void
MainWindow::areaSelected()
{
    if (!m_Webcam)
        return;

    /* TODO: start tracking */
    m_Webcam->startTrackingSelectedArea();
}

void
MainWindow::onTrackingStoped()
{
}

void
MainWindow::updateImageCount()
{
    QSqlQuery    query;
    QString      sql;
    QString      label;
    QSqlDatabase db;

    label = QString("%1").arg(0);
    m_CLImageCount->setText(label);

    sql = QString("SELECT COUNT(code) FROM imagenes_de_calibracion WHERE "
                  "vertical = %1 AND horizontal = %2 AND resolution = %3")
          .arg(m_VertCorners->value())
          .arg(m_HorzCorners->value())
          .arg(m_Resolutions->currentIndex());

    if (db.isOpen() && !query.exec(sql))
        return;

    if (db.isOpen() && query.first()) {
        int  count = 0;
        bool ok    = false;

        count = query.value(0).toInt(&ok);

        if (!ok)
            return;

        label = QString("%1").arg(count);
        m_CLImageCount->setText(label);
    }
}

void
MainWindow::computeCalibrationParameters()
{
    QSqlQuery     query;
    QString       sql;
    QList<QImage> images;
    double        progress          = 0.0;
    double        delta             = 0.0;
    int           lcc               = 0;
    CvMat        *image             = NULL;
    CvPoint2D32f *corners           = NULL;
    CvSize        size              = {m_HorzCorners->value(),
                                       m_VertCorners->value()
                                      };
    CvMat       *image_points[2]   = {NULL};
    CvMat       *object_points[2]  = {NULL};
    CvMat       *point_counts      = NULL;
    CvMat       *intrinsic_matrix	= NULL;
    CvMat       *distortion_coeffs = NULL;
    CvMat       *rotation          = NULL;
    CvMat       *translation       = NULL;
    int          step              = 0;
    int          count             = 0;
    bool         ok                = false;
    QSqlDatabase db;

    m_BTools->setEnabled(false);
    sql = QString("SELECT COUNT(code) FROM imagenes_de_calibracion WHERE "
                  "vertical = %1 AND horizontal = %2 AND resolution = %3")
          .arg(m_VertCorners->value())
          .arg(m_HorzCorners->value())
          .arg(m_Resolutions->currentIndex());

    if (db.isOpen() && !query.exec(sql))
        goto abort;

    if (db.isOpen() && !query.first())
        goto abort;

    count = query.value(0).toInt(&ok);

    if (!ok)
        goto abort;

    sql = QString("SELECT data FROM imagenes_de_calibracion WHERE "
                  "vertical = %1 AND horizontal = %2 AND resolution = %3")
          .arg(m_VertCorners->value())
          .arg(m_HorzCorners->value())
          .arg(m_Resolutions->currentIndex());

    if (db.isOpen() && !query.exec(sql))
        goto abort;

    PROGRESS_MESSAGE("Creando Almacenes...", 5);

    lcc               = size.width * size.height;
    image_points[0]   = cvCreateMat(count * lcc, 2, CV_32FC1);
    object_points[0]  = cvCreateMat(count * lcc, 3, CV_32FC1);

    delta = 40.0 / (double)count;

    PROGRESS_MESSAGE("Cargando Imagenes...", progress = 10);
    while (db.isOpen() && query.next()) {
        QVariant    variant;

        variant = query.value(0);

        if (!qVariantCanConvert<QByteArray>(variant))
            continue;

        images << QImage::fromData(variant.toByteArray(), "PNG");

        PROGRESS_MESSAGE("Cargando Imagenes...", progress);
        progress += delta;
    }
    corners = new CvPoint2D32f[lcc];
    count   = 0;

    PROGRESS_MESSAGE("Procesando Imagenes...", progress);
    for (int i = 0 ; i < images.count() ; i++) {
        QImage qimage(images[i]);
        int    found;

        image = cvCreateMatHeader(qimage.height(), qimage.width(), CV_8UC4);
        cvSetData(image, qimage.bits(), qimage.bytesPerLine());

        ok = (cvFindChessboardCorners(image, size, corners, &found) > 0);
        if (ok && found == lcc) {
            step = count * lcc;
            for (int k = step, j = 0 ; j < lcc ; ++k, ++j ) {
                CV_MAT_ELEM(*(image_points[0]), float, k, 0)  = corners[j].x;
                CV_MAT_ELEM(*(image_points[0]), float, k, 1)  = corners[j].y;
                CV_MAT_ELEM(*(object_points[0]), float, k, 0) = j / 1;
                CV_MAT_ELEM(*(object_points[0]), float, k, 1) = j % 1;
                CV_MAT_ELEM(*(object_points[0]), float, k, 2) = 0.0f;
            }
            count++;
        }
        cvDecRefData(&image);
        cvReleaseMat(&image);

        PROGRESS_MESSAGE("Procesando Imagenes...", progress);

        progress += delta;
    }
    delete[] corners;

    object_points[1]  = cvCreateMat(count * lcc, 3, CV_32FC1);
    image_points[1]   = cvCreateMat(count * lcc, 2, CV_32FC1);
    point_counts      = cvCreateMat(count, 1, CV_32SC1);
    rotation          = cvCreateMat(count, 1, CV_32FC3);
    translation       = cvCreateMat(count, 1, CV_32FC3);
    intrinsic_matrix  = cvCreateMat(3, 3, CV_32FC1);
    distortion_coeffs = cvCreateMat(5, 1, CV_32FC1);

    PROGRESS_MESSAGE("Limpiando...", 85);

    for (int i = 0 ; i < count * lcc ; i++) {
        CV_MAT_ELEM(*(image_points[1]), float, i, 0)  =
            CV_MAT_ELEM(*(image_points[0]), float, i, 0);

        CV_MAT_ELEM(*(image_points[1]), float, i, 1)  =
            CV_MAT_ELEM(*(image_points[0]), float, i, 1);

        CV_MAT_ELEM(*(object_points[1]), float, i, 0) =
            CV_MAT_ELEM(*(object_points[0]), float, i, 0);

        CV_MAT_ELEM(*(object_points[1]), float, i, 1) =
            CV_MAT_ELEM(*(object_points[0]), float, i, 1);

        CV_MAT_ELEM(*(object_points[1]), float, i, 2) =
            CV_MAT_ELEM(*(object_points[0]), float, i, 2);
    }

    for (int i = 0 ; i < count ; i++)
        CV_MAT_ELEM(*point_counts, int, i, 0) = lcc;

    CV_MAT_ELEM(*intrinsic_matrix, float, 0, 0) = 1.0;
    CV_MAT_ELEM(*intrinsic_matrix, float, 1, 1) = 1.0;

    size.width  = images[0].width();
    size.height = images[0].height();

    PROGRESS_MESSAGE("Calculando Par\xe1metros...", 90);
    PROGRESS_MESSAGE("Calculando Par\xe1metros...", 90);
    cvCalibrateCamera2(object_points[1],
                       image_points[1],
                       point_counts,
                       size,
                       intrinsic_matrix,
                       distortion_coeffs,
                       rotation,
                       translation);
    cvSave("/home/ecologia-sensorial/Intrinsecos.xml", intrinsic_matrix);
    cvSave("/home/ecologia-sensorial/Distorsion.xml", distortion_coeffs);

    PROGRESS_MESSAGE("Listo...", 100);
    PROGRESS_MESSAGE("Inactivo", 0);

    showCalibrationDetails();

abort:
    m_BTools->setEnabled(true);
    PROGRESS_MESSAGE("Inactivo", 0);

    for (int i = 0 ; i < 2 ; i++) {
        if (object_points[i])
            cvReleaseMat(&object_points[i]);
        image_points[i] = NULL;
        if (image_points[i])
            cvReleaseMat(&image_points[i]);
        image_points[i] = NULL;
    }

    if (intrinsic_matrix)
        cvReleaseMat(&intrinsic_matrix);
    intrinsic_matrix = NULL;

    if (distortion_coeffs)
        cvReleaseMat(&distortion_coeffs);
    distortion_coeffs = NULL;

    if (point_counts)
        cvReleaseMat(&point_counts);
    point_counts = NULL;

    if (rotation)
        cvReleaseMat(&rotation);
    rotation = NULL;

    if (translation)
        cvReleaseMat(&translation);
    translation = NULL;
}

void
MainWindow::showCalibrationDetails()
{
}

void
MainWindow::clearPlot()
{
    m_Tracker->clearPlot();
}

SaveDialog::SaveDialog(QWidget *parent) :
    QDialog(parent)
{
    QVBoxLayout *layout;
    QLabel      *msg;
    QPushButton *acpt;
    QPushButton *cncl;

    layout = new QVBoxLayout(this);
    msg    = new QLabel("Nombre Base de los Archivos\n\n"
                        "Introduzca el nombre base de (el)los archivo(s).\n"
                        "Los archivos generados se llamaran \n\n<nombre base>_insecto_(%i).csv\n\n"
                        "Donde %i ser\xe1 sustituido por el \xedndice que\n"
                        "identificaba al insecto durante la ejecuci\xf3n\n"
                        "del programa.",
                        this);
    m_LineEdit = new QLineEdit(this);
    m_SVNP     = new QComboBox(this);
    acpt       = new QPushButton("Aceptar", this);
    cncl       = new QPushButton("Cancelar", this);

    m_SVNP->addItem("0");
    for (int i = 2 ; i < 13 ; i++) {
        QString txt;

        txt = QString("%1").arg(2 * i + 1);
        m_SVNP->addItem(txt);
    }

    layout->addWidget(msg);
    layout->addWidget(m_LineEdit);
    layout->addWidget(new QLabel("N\xfamero de puntos del suavizado"));
    layout->addWidget(m_SVNP);
    layout->addWidget(acpt);
    layout->addWidget(cncl);

    connect(acpt, SIGNAL(clicked()), SLOT(accept()));
    connect(cncl, SIGNAL(clicked()), SLOT(reject()));
}

QString
SaveDialog::getText() const
{
    return m_LineEdit->text();
}

int
SaveDialog::getSVNP() const
{
    int     value;
    bool    ok;

    value = m_SVNP->currentText().toInt(&ok);

    if (!ok)
        return 0;

    return value;
}

void
MainWindow::save()
{
    QString         basename;
    QString         basedir;
    SaveDialog      dialog(this);
    QFileDialog     file_dialog;
    int             value;

    basedir  = file_dialog.getExistingDirectory(this, "Guardar", QDir::homePath());

    if (dialog.exec() == QDialog::Rejected)
        return;

    basename = dialog.getText();
    value    = dialog.getSVNP();

    if (basename.isEmpty()) {
        QMessageBox msgbox(this);

        msgbox.setText("No especifico un nombre de archivo.");
        msgbox.setIcon(QMessageBox::Critical);

        msgbox.exec();

        return;
    }

    if (!m_Tracker->saveTrayectories(basename, basedir, value)) {
        QMessageBox msgbox(this);

        msgbox.setText("Error al guardar.");
        msgbox.setIcon(QMessageBox::Critical);

        msgbox.exec();
    }
}
